﻿#ifndef MESH_H
#define MESH_H

#include <string>

#include "glm/vec2.hpp"
#include "glm/vec3.hpp"
#include "Material.h"

#define MAX_BONE_INFLUENCE 4

struct Vertex
{
	glm::vec3 Position;
	glm::vec3 Normal;
	glm::vec2 TexCoords;
	glm::vec3 Tangent;
	glm::vec3 Bitangent;

	/**
	 * 影响这个顶点的骨骼索引
	 */
	int m_BoneIDs[MAX_BONE_INFLUENCE];

	/**
	 * 每个骨头的权重
	 */
	float m_Weights[MAX_BONE_INFLUENCE];
};

class Mesh
{
public:
	std::vector<Vertex> vertices;
	std::vector<unsigned int> indices;
	// std::vector<Texture> textures;
	unsigned int VAO;

	Mesh(const std::vector<Vertex> &vertices, const std::vector<unsigned int> &indices)
	{
		this->vertices = vertices;
		this->indices = indices;
		// this->textures = textures;

		setupMesh();
	}

	~Mesh() = default;

	void Draw(const Material &material) const
	{
		unsigned int diffuseNr = 1;
		unsigned int specularNr = 1;
		unsigned int normalNr = 1;
		unsigned int heightNr = 1;
		for (unsigned int i = 0; i < material.textures.size(); i++)
		{
			glActiveTexture(GL_TEXTURE0 + i); // 在绑定之前激活相应的纹理单元
			// 获取纹理序号（diffuse_textureN 中的 N）
			std::string number;
			std::string name = material.textures[i].type;
			if (name == "texture_diffuse")
				number = std::to_string(diffuseNr++);
			else if (name == "texture_specular")
				number = std::to_string(specularNr++);
			else if (name == "texture_normal")
				number = std::to_string(normalNr++);
			else if (name == "texture_height")
				number = std::to_string(heightNr++);

			// 使用 append 避免多次临时字符串拼接
			std::string uniformName = "material.";
			uniformName += name;
			uniformName += number;
			material.setInt(uniformName, static_cast<int>(i));
			glBindTexture(GL_TEXTURE_2D, material.textures[i].id);
		}
		glActiveTexture(GL_TEXTURE0);

		// 绘制网格
		glBindVertexArray(VAO);
		glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, nullptr);
		glBindVertexArray(0);
	}

private:
	unsigned int VBO, EBO;

	void setupMesh()
	{
		glGenVertexArrays(1, &VAO);
		glGenBuffers(1, &VBO);
		glGenBuffers(1, &EBO);

		glBindVertexArray(VAO);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);

		glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(vertices.size() * sizeof(Vertex)), &vertices[0],
		             GL_STATIC_DRAW);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLsizeiptr>(indices.size() * sizeof(unsigned int)),
		             &indices[0], GL_STATIC_DRAW);

		// 顶点位置
		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), static_cast<void *>(nullptr));
		// 顶点法线
		glEnableVertexAttribArray(1);
		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
		                      reinterpret_cast<void *>(offsetof(Vertex, Normal)));
		// 顶点纹理坐标
		glEnableVertexAttribArray(2);
		glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
		                      reinterpret_cast<void *>(offsetof(Vertex, TexCoords)));
		// 顶点切线
		glEnableVertexAttribArray(3);
		glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
		                      reinterpret_cast<void *>(offsetof(Vertex, Tangent)));
		// 顶点副切线
		glEnableVertexAttribArray(4);
		glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
		                      reinterpret_cast<void *>(offsetof(Vertex, Bitangent)));
		// 骨骼索引
		glEnableVertexAttribArray(5);
		glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), reinterpret_cast<void *>(offsetof(Vertex, m_BoneIDs)));
		// 骨骼权重
		glEnableVertexAttribArray(6);
		glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
		                      reinterpret_cast<void *>(offsetof(Vertex, m_Weights)));

		glBindVertexArray(0);
	}
};


#endif //MESH_H
